package com.pansoft.resmanager;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Base64;
import android.util.Log;

import com.pansoft.appcontext.AppConstant;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * 管理下载的资源文件(表单, 菜单, 图片等)
 * 
 * @author zhangjg
 * @date Jan 6, 2014 4:58:49 PM
 */
public class ResFileManager {
	
	private static final String TAG = "ResFileManager";

	//资源文件所在的根路径, zip文件下载到该目录
	public static final String DOWN_LOAD = AppConstant.APP_ROOT+"/download";
	//public static final String RES_DIR = Environment.getExternalStorageDirectory()+"/ESPMobile/res";
	public static final String RES_DIR = AppConstant.APP_ROOT+"/res";

	//公文，邮箱附件 等下载目录
	public static final String MEETING = AppConstant.APP_ROOT+"/meeting";
	
	//zip文件解压到的资源目录
	public static final String UNZIP_DIR = RES_DIR + "/" + "unzip_res";
	
	//图片所在目录
	public static final String IMAGE_DIR = UNZIP_DIR + "/" + "Image";
	
	//表单所在路径
	public static final String FORM_DIR = UNZIP_DIR + "/" + "Form";
	
	//菜单所在路径
	public static final String PACKAGE_DIR = UNZIP_DIR + "/" + "Package";

	//英文国际化菜单所在路径
	public static final String PACKAGE_EN_DIR = UNZIP_DIR + "/" + "ENPackage";
	
	//更新时将update.zip解压到临时目录
	public static final String UNZIP_TEMP_DIR = RES_DIR + "/" + "unzip_temp";
	
	//临时图片目录
	public static final String TEMP_IMAGE_DIR = UNZIP_TEMP_DIR + "/" + "Image";
	
	//临时菜单目录
	public static final String TEMP_PACKAGE_DIR = UNZIP_TEMP_DIR + "/" + "Package";

	//临时表单目录
	public static final String TEMP_FORM_DIR = UNZIP_TEMP_DIR + "/" + "Form";
	static Handler mHandler;
	private static final int DOWN_UPDATE = 1;  
    
    private static final int DOWN_OVER = 2; 
    private static final int DOWN_EXCEPTION = 3;  
    
    
    private static final int ZIP_START = 4;  
    private static final int ZIP_OVER = 5;  
    
    private static int progress;
    public static boolean interceptFlag = false; 
    private static File zipFile;
    private static DownloadType downtype;
      
	
	
	static{
		
		//创建 /sdcard/ESPMobile/res
		File resDir = new File(RES_DIR);    
		if(!resDir.exists()){
			resDir.mkdirs();
		}
		
		//创建  /sdcard/ESPMobile/res/unzip_res
		File uzipDir = new File(UNZIP_DIR);	
		if(!uzipDir.exists()){
			uzipDir.mkdirs();
		}
		
		//创建  /sdcard/ESPMobile/res/unzip_temp
		File uzipTempDir = new File(UNZIP_TEMP_DIR);	
		if(!uzipTempDir.exists()){
			uzipTempDir.mkdirs();
		}
	}
	
	public static void downloadRes(String url, final DownloadType type, final Handler mHandler1){
		mHandler = mHandler1;
		String filePath = getFilePathFromUrl(url);
		
		zipFile = new File(filePath);
		if(zipFile.exists()){
			zipFile.delete();
		}
		
		 downtype = type; 
		 
		 
		//同步下载, 必须放到子线程
		downloadResSync(url, filePath);
		
		
	
		
	
		
/*		//回调
		new Handler(Looper.getMainLooper()).post(new Runnable() {
			
			@Override
			public void run() {
				if(callback != null){
					callback.onSuccess(type);
				}
			}
		});*/
	}
	
	/**
	 * 根据文件名获取图标
	 * @param fileName 文件名, 不包括路径
	 * @return 可能返回空, 使用该方法的执行结果需要判空
	 */
	public Bitmap getDrawableRes(String fileName){
		
		String imageFilePath = IMAGE_DIR + "/" + fileName;
		InputStream in = getFile(imageFilePath);
		 
//		if(in != null){
			Bitmap bm = BitmapFactory.decodeStream(in);
			
//		}
//		else{
//			return null;
//		}
		return bm;
	}
	
	/**
	 * 根据文件名获取表单
	 * @param fileName 文件名, 不包括路径
	 * @return 可能返回空, 使用该方法的执行结果需要判空
	 */
	public InputStream getFormRes(String fileName){
		
		String formFilePath = FORM_DIR + "/" + fileName;
		return getFile(formFilePath);
		
	}
	
	/**
	 * 根据文件名获取菜单
	 * @param fileName 文件名, 不包括路径
	 * @return 可能返回空, 使用该方法的执行结果需要判空
	 */
	public InputStream getMenuRes(String fileName){
		String formFilePath = PACKAGE_DIR + "/" + fileName;
		return getFile(formFilePath);
	}
	
	/**
	 * 获取资源文件
	 * @param filePath 文件绝对路径
	 * @return
	 */
	public static InputStream getFile(String filePath){
		
		
//		InputStream in = null;
//		try {
//			in = new FileInputStream(filePath);
//			
//		} catch (FileNotFoundException e) {
//			Log.i(TAG, "文件" + filePath + "不存在");
//			e.printStackTrace();
//		}
//		return in;
		
		//读取之前必须先解密文件
		return decryptFile(filePath);
	}

	
	/**
	 * 解压文件并加密
	 */
	public static void unzipAndEncryptFile(String filePath, DownloadType type){
		
		//删除原有的解压缩后的文件
		//deleteUnzipRes();
		ZipUtil zUtil = new ZipUtil();
		boolean issuccessZip ;
		if(type == DownloadType.INIT){  //初始化
			Log.i(TAG, "init, 第一次下载资源");
			
			issuccessZip = zUtil.unZip(filePath, UNZIP_DIR);
			//将加密后的要更新的文件拷贝到资源目录
			if(issuccessZip){
			//资源文件下载并处理完毕
		    mHandler.sendEmptyMessage(ZIP_OVER);
			}
			//encryptAllRes();   //加密所有文件
			
		}else if(type == DownloadType.UPDATE){
			
			Log.i(TAG, "update, 更新资源");
			
			//将更新的zip解压到临时目录
			issuccessZip = zUtil.unZip(filePath, UNZIP_TEMP_DIR);
			
			//encryptAllTempRes();
			
			//将加密后的要更新的文件拷贝到资源目录
			if(issuccessZip){
		 
			copyTempFileToRes();
			//资源文件下载并处理完毕
			mHandler.sendEmptyMessage(ZIP_OVER);
			//删除临时目录中的文件
			deleteTempRes();
		
			}
			
			
		}
		
	} 
	
	/**
	 * 删除临时目录中的文件(不会删除目录结构)
	 */
	public static void deleteTempRes(){
		File tempResRootDir = new File(UNZIP_TEMP_DIR);
		
		for(File resDir : tempResRootDir.listFiles()){
			deleteFileOfDir(resDir.getAbsolutePath());
		}
	}
	/**
	 * 将临时资源文件拷贝到资源目录
	 */
	public static void copyTempFileToRes(){
		copyFile(TEMP_FORM_DIR, FORM_DIR);
		copyFile(TEMP_IMAGE_DIR, IMAGE_DIR);
		copyFile(TEMP_PACKAGE_DIR, PACKAGE_DIR);
	}
	
	
	/**
	 * 删除一个目录下的所有文件, 如果目录下存在目录, 则不会递归删除
	 * @param dir 资源文件所在的父目录
	 */
	public static void deleteFileOfDir(String dir){
		deleteFileOfDir(new File(dir));
	}
	
	/**
	 * 删除一个目录下的所有文件, 如果目录下存在目录, 则不会递归删除
	 * @param dir 资源文件所在的父目录
	 */
	private static void deleteFileOfDir(File dir){
		
		if((!dir.exists())) {  
			Log.i(TAG, "要删除的目录" + dir.getAbsolutePath() + "不存在, 删除失败");
			return;
		}
		
		if(!dir.isDirectory()){
			Log.i(TAG, "要删除的目录" + dir.getAbsolutePath() + "不是目录, 删除失败");
			return;
		}

		for(File f : dir.listFiles()){
			if(f.isFile()){
				f.delete();
			}
		}
	}
	
	/**
	 * 复制文件, 复制后文件名不变
	 * @param resDir	原文件所在目录
	 * @param desDir	目标目录
	 */
	private static void copyFile(String resDir, String desDir){
		File _resDir = new File(resDir);
		File _desDir = new File(desDir);
		
		if((!_resDir.exists()) || (!_desDir.exists())){  //如果目录不存在
			return;
		}
		
		
		for(File f : _resDir.listFiles()){
			if(!f.isFile()){
				continue;
			}
			
			String name = f.getName();
			File desFile = new File(desDir + "/" + name);
			
			if(desFile.exists()){
				desFile.delete();
			}
			
			copyAFile(f, desFile);
			
		}
	}
	
	/**
	 * 复制一个文件
	 * @param resFile
	 * @param desFile
	 */
	private static void copyAFile(File resFile, File desFile){
		BufferedInputStream bufIn = null; 
		BufferedOutputStream bufOut = null;
		
		try {
			bufIn = new BufferedInputStream(new FileInputStream(resFile));
			bufOut = new BufferedOutputStream(new FileOutputStream(desFile));
			int len = 0;
			byte[] buffer = new byte[1024];
			
			while((len = bufIn.read(buffer)) != -1){
				bufOut.write(buffer, 0, len);
			}
			
		} catch (Exception e) {
			Log.i(TAG, "复制临时文件" + resFile.getAbsolutePath() + "时出现错误, 复制失败");
			e.printStackTrace();
		}finally{
			
			if(bufIn != null){
				try {
					bufIn.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
			if(bufOut != null){
				try {
					bufOut.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	/**
	 * 获取要下载的文件的本地储存路径
	 * 该路径是绝对路径
	 * @param url
	 * @return
	 */
	private static String getFilePathFromUrl(String url) {
		
		String fileName = url.substring(url.lastIndexOf("/") + 1); 
		return RES_DIR + "/" + fileName;
	}
	
	/**
	 * init时对所有资源进行加密
	 */
	private static void encryptAllRes(){

		File resRootDir = new File(UNZIP_DIR);
		
		for(File resDir : resRootDir.listFiles()){
			encryptDir(resDir);
		}
//		encryptDir(new File(IMAGE_DIR));
//		encryptDir(new File(PACKAGE_DIR));
//		encryptDir(new File(FORM_DIR));
	}
	
	/**
	 * 更新时对所有临时资源加密
	 */
	private static void encryptAllTempRes(){
		
		File tempRootDir = new File(UNZIP_TEMP_DIR);
		
		for(File tempResDir : tempRootDir.listFiles()){
			encryptDir(tempResDir);
		}

//		encryptDir(new File(TEMP_IMAGE_DIR));
//		encryptDir(new File(TEMP_PACKAGE_DIR));
//		encryptDir(new File(TEMP_FORM_DIR));
	}
	
	/**
	 * 将文件夹下的所有文件分别加密(不会递归加密文件夹)
	 */
	private static void encryptDir(File dirToEncrypt){
		
		for(File file : dirToEncrypt.listFiles()){
			if(file.exists() && file.isFile()){
				encryptFile(file.getAbsolutePath());
			}
		}
	}
	
	
	/***
	 * 返回一个xml的String形式
	 * @param file
	 * @return
	 */
	@SuppressWarnings("resource")
	public static String decryptFile(File file) {
		String result = null;
		// String filePath = file.toString();
		try {
			FileReader fr = new FileReader(file);
			BufferedReader br = new BufferedReader(fr);
			String s = null;
			StringBuilder sb = new StringBuilder();

			while ((s = br.readLine()) != null) {
				sb.append(s);
			}

			result = sb.toString();
			String all =Base64.encodeToString(sb.toString().getBytes(), Base64.DEFAULT);
			byte[] allBytes = Base64.decode(all, Base64.DEFAULT);
			//byte[] decryData = Des3.des3DecodeCBC(allBytes);
			
			//result = new String(decryData);
			
		//	Log.i("DES", result);
			br.close();
			fr.close();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return result;
	}
	
	
	/**
	 * 加密文件
	 * @param filePath  文件绝对路径, 加密之后文件名不变, 覆盖原文件
	 */
	@SuppressWarnings("resource")
	private static void encryptFile(String filePath){
		
		/**
		 * huayang 只加密xml文件
		 */
		Log.i("tag",(FileUtils.getExtensionName(filePath)));
		if(!"xml".equals(FileUtils.getExtensionName(filePath))){
			return;
		}
		
//		File sdDir = Environment.getExternalStorageDirectory();
//		String [] array = sdDir.list();
//		FileInputStream in = null;
//		ByteArrayOutputStream byOut = null;
//		FileOutputStream out = null;
//		try {
//			//File file = new File(filePath);
//			in = new FileInputStream(filePath);
//			BufferedInputStream bis = new BufferedInputStream(in);
//			
//			
//			byOut = new ByteArrayOutputStream();
////			out = new FileOutputStream(filePath);
//			
//			byte[] buffer = new byte[1024];
//			
//			int len = 0;
//			len = in.read(buffer);
//			len = bis.read(buffer);
//			while((len = in.read(buffer)) != -1){
//				byOut.write(buffer, 0, len);
//			}
//			byte[] b =  byOut.toByteArray();
//			byte[] encodedByteArray = Des3.des3EncodeCBC(byOut.toByteArray());
//			
//			out = new FileOutputStream(filePath);
//			out.write(encodedByteArray);
		try{
			
			FileReader fr = new FileReader(new File(filePath));
			BufferedReader br = new BufferedReader(fr);
			String s = null;
			StringBuilder sb = new StringBuilder();
			
			while((s = br.readLine()) != null){
				sb.append(s);
			}
			
			String all = sb.toString();
			byte[] data = all.getBytes();
			Log.i("LEN :"," byte[] data = all.getBytes(); " + data.length);	
			
			byte[] encodedByteArray = Des3.des3EncodeCBC(data);
			Log.i("LEN :"," 加密完后的长度" + encodedByteArray.length);	
			Log.i("LEN :","加密 ：\n" + new String(encodedByteArray));
			
			byte[] back = Des3.des3DecodeCBC(encodedByteArray);
			Log.i("LEN :","恢复 ：\n" + new String(back));
			Log.i("LEN :"," 解密完后的长度" + back.length);
			
			FileOutputStream fout = new FileOutputStream(filePath,false);
			BufferedOutputStream bout = new BufferedOutputStream(fout);
			bout.write(encodedByteArray);
			bout.flush();
			bout.close();
			
			fr.close();
			br.close();
		} catch (Exception e) {
			e.printStackTrace();
			Log.i(TAG, "文件" + filePath + "在加密过程中出现错误, 加密失败");
		}finally{
			
//			if(in != null){
//				try {
//					in.close();
//				} catch (IOException e) {
//					e.printStackTrace();
//				}
//			}
//			
//			if(out != null){
//				try {
//					out.close();
//				} catch (IOException e) {
//					e.printStackTrace();
//				}
//			}
//			
//			if(byOut != null){
//				try {
//					byOut.close();
//				} catch (IOException e) {
//					e.printStackTrace();
//				}
//			}
		}
	}
	
	/**
	 * 解密文件
	 * @param filePath
	 */
	private static InputStream decryptFile(String filePath){
		
		FileInputStream in = null;
		ByteArrayOutputStream byOut = null;
		ByteArrayInputStream byIn = null;
		try {
			byOut = new ByteArrayOutputStream();
			in = new FileInputStream(filePath);
			byte[] buffer = new byte[1024];
			int len = 0;
			while((len = in.read(buffer)) != -1){
				byOut.write(buffer, 0, len);
			}
			
			byte[] decodedByteArray = Des3.des3EncodeCBC(byOut.toByteArray());
			
			byIn = new ByteArrayInputStream(decodedByteArray);
		} catch (Exception e) {
			e.printStackTrace();
			Log.i(TAG, "文件" + filePath + "在解密过程中出现错误, 解密失败");
		}finally{
			if(in != null){
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
			if(byOut != null){
				try {
					byOut.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return byIn;
	}
	
	/**
	 * 同步下载
	 */
	private static void downloadResSync(String url1, String filePath){
		
		/*HttpUtils http = new HttpUtils();
		http.configCurrentHttpCacheExpiry(1000*5);
		http.configRequestThreadPoolSize(3);
		ResponseStream responseStream = null;*/
		 try {  
             URL url = new URL(url1);  
           
             HttpURLConnection conn = (HttpURLConnection)url.openConnection();  
             conn.connect();  
             conn.setConnectTimeout(1000*5);
             int length = conn.getContentLength();  
             InputStream is = conn.getInputStream();  
               
            /* File file = new File(filePath);  
             if(!file.exists()){  
                 file.mkdir();  
             }  
             String apkFile = saveFileName;  
             File ApkFile = new File(apkFile);*/  
             FileOutputStream fos = new FileOutputStream(filePath);  
               
             int count = 0;  
             byte buf[] = new byte[1024];  
               
             do{                   
                 int numread = is.read(buf);  
                 count += numread;  
                 progress =(int)(((float)count / length) * 100);  
                 //更新进度   
                 Message msg = new Message();
                 Bundle b = new Bundle();// 存放数据
                 b.putInt("progress", progress);
                 msg.setData(b);
                 msg.what = DOWN_UPDATE;   
                 mHandler.sendMessage(msg);
                 //mHandler.sendEmptyMessage(DOWN_UPDATE);  
                 if(numread <= 0){      
                     //下载完成通知安装   
                      
                     break;  
                 }  
                 fos.write(buf,0,numread);  
             }while(!interceptFlag);//点击取消就停止下载.   
               
             fos.close();  
             is.close();  
             //如果没有中断下载
             if(!interceptFlag){
            mHandler.sendEmptyMessage(DOWN_OVER);
         	//解压文件并加密
            mHandler.sendEmptyMessage(ZIP_START);
     		unzipAndEncryptFile(filePath, downtype);
     		//删除下载的源文件
     		zipFile.delete();
             }else {
          		//删除下载的更新文件
          		zipFile.delete();
          		/*String path = Environment.getExternalStorageDirectory()
    					.getAbsolutePath() + File.separator + "espmobile";
    			File espMobile = new File(path);
    			//删除整个espmobile目录
    			deleteFile(espMobile);*/
			}
         } catch (MalformedURLException e) {  
             e.printStackTrace();  
             mHandler.sendEmptyMessage(DOWN_EXCEPTION);
         } catch(IOException e){  
             e.printStackTrace(); 
             mHandler.sendEmptyMessage(DOWN_EXCEPTION);
         }
		 

		
		/*try {
			Log.i("xxxx",url);
			responseStream = http.sendSync(HttpRequest.HttpMethod.GET, 
					url);
			responseStream.readFile(filePath);
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			
			if(responseStream != null){
				try {
					responseStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}*/
	}
	
	public static enum DownloadType{
		INIT,
		UPDATE
	}
	
	/**
	 * 删除文件夹所有内容
	 *
	 */
	public static void deleteFile(File file) {

		if (file.exists()) { // 判断文件是否存在
			if (file.isFile()) { // 判断是否是文件
				file.delete(); // delete()方法 你应该知道 是删除的意思;
			} else if (file.isDirectory()) { // 否则如果它是一个目录
				File files[] = file.listFiles(); // 声明目录下所有的文件 files[];
				for (int i = 0; i < files.length; i++) { // 遍历目录下所有的文件
					deleteFile(files[i]); // 把每个文件 用这个方法进行迭代
				}
			}
			file.delete();
		} else {
			//
		}
	}



	/**
		 * 解压assets的zip压缩文件到指定目录
		 * @param context 上下文对象
		 * @param assetName 压缩文件名
		 * @param outputDirectory 输出目录
		 * @param isReWrite 是否覆盖
		 * @throws IOException
		 */
		public static void unZipAssetsToSD(Context context, String assetName, String outputDirectory, boolean isReWrite) throws IOException {
			// 创建解压目标目录
			File file = new File(outputDirectory);
			// 如果目标目录不存在，则创建
			if (!file.exists()) {
				file.mkdirs();
			}
			// 打开压缩文件
			InputStream inputStream = context.getAssets().open(assetName);
			ZipInputStream zipInputStream = new ZipInputStream(inputStream);
			// 读取一个进入点
			ZipEntry zipEntry = zipInputStream.getNextEntry();
			// 使用1Mbuffer
			byte[] buffer = new byte[1024 * 1024];
			// 解压时字节计数
			int count = 0;
			// 如果进入点为空说明已经遍历完所有压缩包中文件和目录
			while (zipEntry != null) {
				// 如果是一个目录
				if (zipEntry.isDirectory()) {
					file = new File(outputDirectory + File.separator + zipEntry.getName());
					// 文件需要覆盖或者是文件不存在
					if (isReWrite || !file.exists()) {
						file.mkdir();
					}
				} else {
					// 如果是文件
					file = new File(outputDirectory + File.separator + zipEntry.getName());
					// 文件需要覆盖或者文件不存在，则解压文件
					if (isReWrite || !file.exists()) {
						if (!file.getParentFile().exists()){
							file.getParentFile().mkdirs();
						}
						file.createNewFile();
						FileOutputStream fileOutputStream = new FileOutputStream(file);
						while ((count = zipInputStream.read(buffer)) > 0) {
							fileOutputStream.write(buffer, 0, count);
						}
						fileOutputStream.close();
					}
				}
				// 定位到下一个文件入口
				zipEntry = zipInputStream.getNextEntry();
			}
			zipInputStream.close();
		}

    /**
     * 解压assets的zip压缩文件到指定目录
     * 使用ant.jar方法来解压，解决中文乱码的问题
     *
     * @param context         上下文对象
     * @param assetName       压缩文件名
     * @param outputDirectory 输出目录
     * @param isReWrite       是否覆盖
     * @throws IOException
     */
    public static void unZipAssetsToSDUsingAnt(Context context, String assetName, String outputDirectory, boolean isReWrite) throws IOException {
		// 创建解压目标目录
		File file = new File(outputDirectory);
		// 如果目标目录不存在，则创建
		if (!file.exists()) {
			file.mkdirs();
		}
		// 打开压缩文件
		InputStream inputStream = context.getAssets().open(assetName);
		ZipInputStream zipInputStream = new ZipInputStream(inputStream);
		// 读取一个进入点
		ZipEntry zipEntry = zipInputStream.getNextEntry();
		// 使用1Mbuffer
		byte[] buffer = new byte[1024 * 1024];
		// 解压时字节计数
		int count = 0;
		// 如果进入点为空说明已经遍历完所有压缩包中文件和目录
		while (zipEntry != null) {
			file = new File(outputDirectory + File.separator + zipEntry.getName());

			if (zipEntry.isDirectory()) {
				file.mkdirs();
			} else {
				// 如果指定文件的目录不存在,则创建之.
				File parent = file.getParentFile();
				if (!parent.exists()) {
					parent.mkdirs();
				}

				FileOutputStream fileOutputStream = new FileOutputStream(file);
				while ((count = zipInputStream.read(buffer)) > 0) {
					fileOutputStream.write(buffer, 0, count);
				}
				fileOutputStream.close();
			}
			// 定位到下一个文件入口
			zipEntry = zipInputStream.getNextEntry();
		}
		zipInputStream.close();
    }
}
